package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.validation.Valid;
import java.util.Date;
import java.util.List;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/7/29 15:44
 * @Version 1.0
 */
@Component
public class SeckillReceiver {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @SneakyThrows
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_TASK_1,durable = "true",autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
                    key = {MqConst.ROUTING_TASK_1}
            )
    )
    public void importToRedis(String msg,Message message , Channel channel){
        try {
            //  执行sql 语句.
            //  select * from seckill_goods where date_format(start_time,'%Y-%m-%d')  = (select date_format(now(),'%Y-%m-%d') from dual) and status = '1' and stock_count > 0;
            //  构建查询条件
            LambdaQueryWrapper<SeckillGoods> seckillGoodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
            seckillGoodsLambdaQueryWrapper.eq(SeckillGoods::getStatus,"1").gt(SeckillGoods::getStockCount,0);
            seckillGoodsLambdaQueryWrapper.apply("DATE_FORMAT(start_time,'%Y-%m-%d') = " + "'" + DateUtil.formatDate(new Date()) + "'");
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsLambdaQueryWrapper);

            //  循环遍历将数据存储到缓存.
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                //seckillGoodsList.forEach(seckillGoods -> {
                for (SeckillGoods seckillGoods : seckillGoodsList) {
                    //  判断缓存中是否有该商品
                    String seckillGoodsKey = RedisConst.SECKILL_GOODS;
                    Boolean result = this.redisTemplate.opsForHash().hasKey(seckillGoodsKey, seckillGoods.getSkuId().toString());
                    if (result){
                        //  缓存中有数据不能覆盖.
                        //  return; break; continue; 区别！
                        continue;
                    }
                    //  必须考虑缓存的是数据类型，key; hash 数据类型. hset key field value;
                    redisTemplate.opsForHash().put(seckillGoodsKey,seckillGoods.getSkuId().toString(),seckillGoods);
                    //  如何防止用户超卖的问题！可以将商品的剩余库存数统一放入redis-list 队列中.
                    for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
                        //  lpush key=seckill:stock:skuId value=skuId;
                        this.redisTemplate.opsForList().leftPush(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId(),seckillGoods.getSkuId().toString());
                        //  rpop key =seckill:stock:skuId
                    }
                    //  skuId:1 publish seckillpush 25:1
                    this.redisTemplate.convertAndSend("seckillpush",seckillGoods.getSkuId()+":1");
                }
                //});
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //  手动签收
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //  监听用户秒杀信息
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER),
            key = {MqConst.ROUTING_SECKILL_USER}
    ))
    public void seckillUser(UserRecode userRecode,Message message ,Channel channel){
        try {
            //  判断
            if (null != userRecode){
                //  消费消息业务处理
                seckillGoodsService.seckillUser(userRecode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //  确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    //  监听减库存消息.
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConst.QUEUE_SECKILL_STOCK,durable = "true",autoDelete = "false"),
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_STOCK),
            key = {MqConst.ROUTING_SECKILL_STOCK}
    ))
    public void seckillStock(Long skuId,Message message, Channel channel){
        try {
            //  判断
            if (null != skuId){
                //  调用减库存方法.
                seckillGoodsService.updateStock(skuId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //  手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    /**
     * 清空缓存数据
     * @param msg
     * @param message
     * @param channel
     */
    @SneakyThrows
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(value = MqConst.QUEUE_TASK_18,durable = "true",autoDelete = "false"),
                    exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK),
                    key = {MqConst.ROUTING_TASK_18}
            )
    )
    public void clearData(String msg,Message message , Channel channel){
        try {
            //  查询当前结束的秒杀商品.
            //  构建查询条件
            LambdaQueryWrapper<SeckillGoods> seckillGoodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
            seckillGoodsLambdaQueryWrapper.eq(SeckillGoods::getStatus,"1");
            //  DateUtil.formatDate(new Date()) 只格式化的是年月日;
            seckillGoodsLambdaQueryWrapper.le(SeckillGoods::getEndTime,new Date());
            List<SeckillGoods> seckillGoodsList = seckillGoodsMapper.selectList(seckillGoodsLambdaQueryWrapper);
            if (!CollectionUtils.isEmpty(seckillGoodsList)){
                for (SeckillGoods seckillGoods : seckillGoodsList) {
                    //  删除秒杀的剩余库存:
                    //  seckill:stock:25
                    this.redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX+seckillGoods.getSkuId());
                }
            }
            //  秒杀商品集合
            this.redisTemplate.delete(RedisConst.SECKILL_GOODS);
            //  删除预下单数据: this.redisTemplate.opsForHash().put(RedisConst.SECKILL_ORDERS,userRecode.getUserId(),orderRecode);
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS);
            //  删除真正下单数据
            this.redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //  手动确认
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
